const mongoose = require("mongoose");
const Warehouse = require("../models/warehouseModel");
const Item = require("../models/itemModel");
const StockAdjustment = require("../models/stockAdjustmentModel");
const StockTransfer = require("../models/stockTransferModel");
const Inventory = require("../models/inventoryModel");

// Create a new warehouse
exports.createWarehouse = async (req, res) => {
  try {
    const { warehouseName, mobile, email, status, Latitude, Longitude } = req.body;

    if (!warehouseName) {
      return res.status(400).json({ success: false, message: "Warehouse name is required" });
    }

    const location = {
      type: "Point",
      coordinates: [Number(Longitude), Number(Latitude)]
    };

    const newWarehouse = new Warehouse({
      warehouseName,
      mobile,
      email,
      status,
      Latitude,
      Longitude,
      location  
    });

    await newWarehouse.save();
    return res.status(201).json({
      success: true,
      message: "Warehouse created successfully",
      data: newWarehouse,
    });
  } catch (error) {
    return res.status(500).json({ success: false, message: error.message });
  }
};

// Get all warehouses
exports.getAllWarehouses = async (req, res) => {
  try {
    const warehouses = await Warehouse.find().sort({ warehouseName: 1 });
    return res.status(200).json({ success: true, data: warehouses });
  } catch (error) {
    return res.status(500).json({ success: false, message: error.message });
  }
};

// Get a single warehouse by id
exports.getWarehouseById = async (req, res) => {
  try {
    const warehouse = await Warehouse.findById(req.params.id);
    if (!warehouse) {
      return res.status(404).json({ success: false, message: "Warehouse not found" });
    }
    return res.status(200).json({ success: true, data: warehouse });
  } catch (error) {
    return res.status(500).json({ success: false, message: error.message });
  }
};

// Update warehouse information
exports.updateWarehouse = async (req, res) => {
  try {
    if (req.body.Latitude && req.body.Longitude) {
      req.body.location = {
        type: "Point",
        coordinates: [Number(req.body.Longitude), Number(req.body.Latitude)]
      };
    }
    const updatedWarehouse = await Warehouse.findByIdAndUpdate(req.params.id, req.body, { new: true });
    if (!updatedWarehouse) {
      return res.status(404).json({ success: false, message: "Warehouse not found" });
    }
    return res.status(200).json({
      success: true,
      message: "Warehouse updated successfully",
      data: updatedWarehouse,
    });
  } catch (error) {
    return res.status(500).json({ success: false, message: error.message });
  }
};

// Delete a warehouse
exports.deleteWarehouse = async (req, res) => {
  try {
    const deletedWarehouse = await Warehouse.findByIdAndDelete(req.params.id);
    if (!deletedWarehouse) {
      return res.status(404).json({ success: false, message: "Warehouse not found" });
    }
    return res.status(200).json({ success: true, message: "Warehouse deleted successfully" });
  } catch (error) {
    return res.status(500).json({ success: false, message: error.message });
  }
};

// Get nearby warehouses using geospatial query
exports.getNearbyWarehouses = async (req, res) => {
  try {
    const { latitude, longitude, maxDistance } = req.query;
    if (!latitude || !longitude) {
      return res.status(400).json({ success: false, message: "latitude and longitude query parameters are required" });
    }
    const lat = parseFloat(latitude);
    const lng = parseFloat(longitude);
    const distance = maxDistance ? parseInt(maxDistance) : 5000; // default 5000 meters

    const warehouses = await Warehouse.find({
      location: {
        $near: {
          $geometry: { type: "Point", coordinates: [lng, lat] },
          $maxDistance: distance,
        },
      },
    });
    return res.status(200).json({ success: true, data: warehouses });
  } catch (error) {
    return res.status(500).json({ success: false, message: error.message });
  }
};


exports.getWarehouseInventory = async (req, res) => {
  try {
    const warehouseId = req.params.id;
    
    // Get all ledger records for the warehouse.
    // The ledger will include any (warehouse, item) record that has been updated via transactions.
    const ledgerRecords = await Inventory.find({
      warehouse: new mongoose.Types.ObjectId(warehouseId)
    }).select("item quantity").lean();
    
    // For each ledger record, get the detailed breakdown.
    const detailedInventory = await Promise.all(
      ledgerRecords.map(async (ledgerRecord) => {
        const itemId = ledgerRecord.item;
        
        // Fetch the master item data including its original warehouse assignment.
        const item = await Item.findById(itemId)
          .select("itemName sku openingStock description warehouse")
          .lean();
          
        // Check if the item was originally assigned to this warehouse.
        // If yes, use its openingStock; otherwise, treat the openingStock as 0.
        const openingStock = (item && item.warehouse && item.warehouse.toString() === warehouseId)
          ? (item.openingStock || 0)
          : 0;
        
        // Calculate Total Adjustments.
        const adjustmentsAgg = await StockAdjustment.aggregate([
          { $match: { warehouse: new mongoose.Types.ObjectId(warehouseId), "items.item": itemId } },
          { $unwind: "$items" },
          { $match: { "items.item": itemId } },
          { $group: { _id: null, totalAdjustment: { $sum: "$items.quantity" } } }
        ]);
        const totalAdjustment = adjustmentsAgg[0] ? adjustmentsAgg[0].totalAdjustment : 0;
        
        // Calculate Total Transfers Out (where warehouse is the sender).
        const transfersOutAgg = await StockTransfer.aggregate([
          { $match: { fromWarehouse: new mongoose.Types.ObjectId(warehouseId) } },
          { $unwind: "$items" },
          { $match: { "items.item": itemId } },
          { $group: { _id: null, totalOut: { $sum: "$items.quantity" } } }
        ]);
        const totalOut = transfersOutAgg[0] ? transfersOutAgg[0].totalOut : 0;
        
        // Calculate Total Transfers In (where warehouse is the receiver).
        const transfersInAgg = await StockTransfer.aggregate([
          { $match: { toWarehouse: new mongoose.Types.ObjectId(warehouseId) } },
          { $unwind: "$items" },
          { $match: { "items.item": itemId } },
          { $group: { _id: null, totalIn: { $sum: "$items.quantity" } } }
        ]);
        const totalIn = transfersInAgg[0] ? transfersInAgg[0].totalIn : 0;
        
        // Calculate current stock based on the detailed aggregation.
        const currentStock = openingStock + totalAdjustment + totalIn - totalOut;
        
        // Return a combined record.
        return {
          itemName: item ? item.itemName : "Unknown item",
          sku: item ? item.sku : null,
          description: item ? item.description : "",
          openingStock,
          totalAdjustment,
          totalIn,
          totalOut,
          ledgerQuantity: ledgerRecord.quantity, // the net value stored in the ledger
          currentStock
        };
      })
    );
    
    return res.status(200).json({ success: true, data: detailedInventory });
  } catch (error) {
    return res.status(500).json({ success: false, message: error.message });
  }
};